﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Reflection;
using System.Web.Routing;
using System.Collections;
using System.Text;

namespace Wicresoft.SMS.Web
{
    public static class AuthorisedControlHelper
    {
        #region AuthorisedActionLink
        public static string AuthorisedActionLink(this HtmlHelper html, object model, string expression, string actionName){
            return html.AuthorisedActionLink(model, expression, null /* linkText */, actionName, null /* controller */, new RouteValueDictionary(), new RouteValueDictionary());
        }

        public static string AuthorisedActionLink(this HtmlHelper html, object model, string expression, string linkText, string actionName)
        {
            return html.AuthorisedActionLink(model, expression, linkText, actionName, null /* controller */, new RouteValueDictionary(), new RouteValueDictionary());
        }

        public static string AuthorisedActionLink(this HtmlHelper html, object model, string expression, string linkText, string actionName, object routeValues)
        {
            return html.AuthorisedActionLink(model, expression, linkText, actionName, null /*controller*/, new RouteValueDictionary(routeValues));
        }

        public static string AuthorisedActionLink(this HtmlHelper html, object model, string expression, string linkText, string actionName, object routeValues, object htmlAttributes)
        {
            return html.AuthorisedActionLink(model, expression, linkText, actionName, null /*controller*/, new RouteValueDictionary(routeValues), new RouteValueDictionary(htmlAttributes));
        }

        public static string AuthorisedActionLink(this HtmlHelper html, object model, string expression, string linkText, string actionName, RouteValueDictionary routeValues)
        {
            return html.AuthorisedActionLink(model, expression, linkText, actionName, null /*controller*/, routeValues, new RouteValueDictionary());
        }

        public static string AuthorisedActionLink(this HtmlHelper html, object model, string expression, string linkText, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
        {
            return html.AuthorisedActionLink(model, expression, linkText, actionName, null /*controller*/ , routeValues, htmlAttributes);
        }

        public static string AuthorisedActionLink(this HtmlHelper html, object model, string expression, string linkText, string actionName, string controllerName)
        {
            return html.AuthorisedActionLink(model , expression , linkText, actionName, controllerName, new RouteValueDictionary(), new RouteValueDictionary());
        }

        public static string AuthorisedActionLink(this HtmlHelper html, object model, string expression, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
        {
            return html.AuthorisedActionLink(model, expression ,linkText, actionName, controllerName, new RouteValueDictionary(routeValues) , new RouteValueDictionary(htmlAttributes));
        }

        public static string AuthorisedActionLink(this HtmlHelper html, object model, string expression, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes){

            AuthorisedMetadataModel _metadata = GetAuthorisedMetadataModel(model, expression);
            IAuthorise _authorise = _metadata.GetAuthoriseProvider();
            if (!_authorise.IsVisible)
                //return MvcHtmlString.Empty.;
                return string.Empty;

            string Display = linkText;
            if (Display == null)
                Display = _metadata.Display;            
            return HtmlHelper.GenerateLink(html.ViewContext.RequestContext, html.RouteCollection, Display, null/* routeName */, actionName, controllerName, routeValues, htmlAttributes);
            //return html.ActionLink(Display, actionName, controllerName, routeValues, htmlAttributes);
        }

        #endregion

        #region AuthorisedInput
        public static MvcHtmlString AuthorisedInput(this HtmlHelper html, object model, string expression){
            return html.AuthorisedInput(model, expression, new RouteValueDictionary());
        }

        public static MvcHtmlString AuthorisedInput(this HtmlHelper html, object model, string expression, object htmlAttributes){
            return html.AuthorisedInput(model, expression, new RouteValueDictionary(htmlAttributes));
        }

        public static MvcHtmlString AuthorisedInput(this HtmlHelper html, object model, string expression, RouteValueDictionary htmlAttributes){
            AuthorisedMetadataModel _metadata = GetAuthorisedMetadataModel(model, expression);
            IAuthorise _authorise = _metadata.GetAuthoriseProvider();
            if (!_authorise.IsVisible)
                return MvcHtmlString.Empty;

            AuthorisedInputRender._model = _metadata;
            Func<TagBuilder[]> thunk;
            if (AuthorisedInputRender.RenderMap.TryGetValue(_metadata.ControlType, out thunk))
            {
                TagBuilder[] tags = thunk();
                if (tags != null)
                {
                    foreach (var at in htmlAttributes)
                        tags[0].MergeAttribute(at.Key, at.Value.ToString(), true);
                }
                StringBuilder sb = new StringBuilder();
                foreach (var tag in tags){
                    if(tag != null)
                        sb.Append(tag.ToString());
                }

                return MvcHtmlString.Create(sb.ToString());
            }

            return MvcHtmlString.Empty;
        }

        #endregion


        public static  IAuthoriseMetadataProvider CreateIAuthoriseMetadataProvider(object model, string expression)
        {
            if (model == null)
                throw new ArgumentNullException("model object is null");
            if (string.IsNullOrEmpty(expression))
                throw new ArgumentNullException("expression is null or empty");
            Type modelType = model.GetType();
            PropertyInfo property = modelType.GetProperty(expression /*,BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty*/);
            if (property == null)
                throw new NullReferenceException(string.Format("the property \"{0}\" is not exists", expression));

            AuthoriseMetadataProviderAttribute attribute;
            if(property.IsDefined(typeof(AuthoriseMetadataProviderAttribute), false))//not allow inherit class search
            {
                attribute = property.GetCustomAttributes(typeof(AuthoriseMetadataProviderAttribute), false)[0] as AuthoriseMetadataProviderAttribute;
                if (attribute == null)
                    throw new Exception("can't cast to AuthoriseMetadataProviderAttribute");
                return attribute.CreateIAuthoriseMetadataProvider(property,model,property);
            }
            if (modelType.IsDefined(typeof(AuthoriseMetadataProviderAttribute), true))//allow inherit class search
            {
                attribute = modelType.GetCustomAttributes(typeof(AuthoriseMetadataProviderAttribute), false)[0] as AuthoriseMetadataProviderAttribute;
                if (attribute == null)
                    throw new Exception("can't cast to AuthoriseMetadataProviderAttribute");
                return attribute.CreateIAuthoriseMetadataProvider(property,model,property);
            }

            DefalutAuthoriseMetadataProvider provider = new DefalutAuthoriseMetadataProvider(model,property);
            return provider;
        }

        public static AuthorisedMetadataModel GetAuthorisedMetadataModel(object model, string expression)
        {
            if (model == null)
                throw new ArgumentNullException("model object is null");
            if (string.IsNullOrEmpty(expression))
                throw new ArgumentNullException("expression is null or empty");

            IAuthoriseMetadataProvider provider = CreateIAuthoriseMetadataProvider(model, expression);
            if (provider == null)
                throw new NullReferenceException("provider is null");
            AuthorisedMetadataModel metadataModel = provider.CreateAuthorisedMetadataModel();
            if (metadataModel == null)
                throw new NullReferenceException("metadataModel is null");

            return metadataModel;
        }

    }
}